#include "jlinkflashprogram.h"
#include "jlinkarm.h"
#include <stdio.h>

/**
 * 
 * @return 0: success, <0: fail
*/
int program_flash_data(u32 addr, u32 size, u8* pdata)
{
    logI("Download data to flash...");
    if (!pdata) {
        logE("pdata is null");
        return -1;
    }
    JLINKARM_Reset();
    JLINKARM_BeginDownload(0);
    JLINKARM_WriteMem(addr, size, pdata);
    JLINKARM_EndDownload();
    logI("O.K.");
    return 0;
}

/**
 * 
 * @return 0: success, <0: fail
*/
int program_bin_file(const char *filename, u32 addr)
{
    FILE *fp;
    fp = fopen(filename, "rb");
    if (fp == NULL)
    {
        logE("open file error");
        return -1;
    }
    fseek(fp, 0, SEEK_END);
    u32 file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    u8* pbuffer = (u8*)malloc(file_size);
    if (pbuffer == NULL)
    {
        logE("malloc error");
        return -2;
    }

    if (fread(pbuffer, 1, file_size, fp) != file_size)
    {
        logE("read file error");
        return -3;
    }
    fclose(fp);

    if (program_flash_data(addr, file_size, pbuffer) < 0)
    {
        logE("program flash error");
        return -4;
    }

    logI("Starting target application...");
    JLINKARM_Reset();
    JLINKARM_Go();
    logI("O.K.");
    return 0;
}

/**
 * support file type: .bin, .hex, .mot .s19 .s, .srec 
*/
int program_file(const char *filename, u32 addr)
{
    int ret = -1;
    logI("Download file:[%s] to flash...", filename);
    JLINKARM_Reset();
    //JLINK_EraseChip();
    if (!filename) {
        logE("arg filename is null");
        return -1;
    }
    if (!JLINK_DownloadFile) {
        logE("arg JLINK_DownloadFile is null");
        return -1;
    }
    ret = JLINK_DownloadFile(filename, addr);
    if (ret < 0)
    {
        logE("JLINK_DownloadFile error");
        return -2;
    }
    logI("O.K.");
    Sleep(2000);
    logI("Starting target application...");
    JLINKARM_Reset();
    JLINKARM_Go();
    return ret;
}

/**
 * erase chip
 * @return 
 *      >=0: success, 
 *      <0: erorr
*/
int program_erase_chip(void)
{
    logI("Erase chip...");
    int ret = JLINK_EraseChip();
    if (ret < 0) {
        logE("erase chip error, ret:%d", ret);
        return -1;
    }
    logI("O.K.");
    return 0;
}